const service = require("../utils/request");
const { setSocket } = require("../utils/msgSave");
const { wcsUrl, wcsSnAllPalletizingApi, wcsData } = require("../utils/config");
const {
  getProductionById,
  updateProductionById,
  getProductionByPalletCode,
} = require("../utils/getProduction");

const {
  snresultHandle,
  csxOneFinish,
  csxFinishAll,
  csxFree,
} = require("../routes/chuanshuxian/index");
const { insertCameraCompareData } = require("../utils/cameraCompare");

const { checkPointInArea } = require("../utils/tools");
const logger = require("../utils/loggers");
// 存储正在处理的产品
const processingProducts = [{}, {}, {}, {}];
// 定义常量 - 优化参数以提高性能
const TIMEOUT = 10; // 超时时间，单位为毫秒
const RETRY_INTERVAL = 100; // 减少重试间隔时间，从500ms降到100ms，提高响应速度
const DIFF_VALUE = 1000; // 差值阈值
const CAMERA_MAX_RETRY = 4; // 减少相机最大重试次数
const STATIC_SIZE = 500; // 静态尺寸值
const MAX_ROBOTS = 4; // 最大机器人数量
const BATCH_SIZE = 120; // 批量读取大小，保持最大值以提高效率

// 调整轮询间隔以提高性能
const POLLING_INTERVAL = 300; // 减少轮询间隔，从500ms降到200ms，提高响应速度

// 定义一个队列
const queue = [0, 0, 0, 0];

// 用于前端通知的标题和事件名
const title = "抓取码垛信息";
const eventName = "clientHandle";

// WCS请求函数
const tartConveyTaskArmHandle = (data) => {
  return service({
    url: wcsUrl + wcsSnAllPalletizingApi,
    method: "post",
    data,
  });
};

// modbus 数据状态获取 读取输入寄存器
const aryList = [
  Array.from({ length: 50 }, (_, i) => i),
  Array.from({ length: 50 }, (_, i) => i + 50),
  Array.from({ length: 50 }, (_, i) => i + 100),
  Array.from({ length: 50 }, (_, i) => i + 150),
];

// 新增 flagList 用于判断是否读取数据
const flagList = [32, 33];

// 商品的写入保持寄存器地址
const writeModBusList = [
  Array.from({ length: 25 }, (_, i) => i * 2 + 1),
  Array.from({ length: 25 }, (_, i) => i * 2 + 51),
  Array.from({ length: 25 }, (_, i) => i * 2 + 101),
  Array.from({ length: 25 }, (_, i) => i * 2 + 151),
];

// 默认配置，可从数据库或接口动态获取
let writingConfig = Array.from({ length: 4 }, () => Array(25).fill(0));

let aryModbusStatusList = [];

// 相机列表
const cameraList = new Array(4).fill(null);
const reqList = new Array(4).fill(null);

// 相机计数器
const cameraCount = new Array(MAX_ROBOTS).fill(null).map(() => ({
  flag: false, // 是否执行过拍照
  value: 0, // 拍照次数
}));

// 整体完成标志
const finishAll = new Array(MAX_ROBOTS)
  .fill(null)
  .map(() => ({ flag: false, flag1: false }));

// 单个完成标志 加两个锁
const finishOne = new Array(MAX_ROBOTS)
  .fill(null)
  .map(() => ({ flag: false, flag1: false }));

// 清除数据
const clearCount = new Array(MAX_ROBOTS).fill(null).map(() => ({
  flag: false, // 是否执行清空数据
}));

/**
 * 获取默认机器人状态
 * @returns {object} 默认机器人状态
 */
function getDefaultRobotStatus() {
  return {
    robotStatus: 0,
    robotPosition: 0,
    robotPhotoStatus: 0,
    robotAllFinished: 0,
    robotOneFinished: 0,
  };
}

/**
 * 验证索引是否有效
 * @param {number} index - 索引
 * @param {number} maxLength - 最大长度
 * @returns {boolean} 索引是否有效
 */
function isValidIndex(index, maxLength) {
  return typeof index === "number" && index >= 0 && index < maxLength;
}

/**
 * 重置所有标志位
 * @param {number} index - 机器人索引
 * way
 */
function resetFlags(index, way = 1) {
  if (way == 0) {
    // 传输尺寸的时候，才会置空
    // 全部码垛完成;
    if (
      isValidIndex(index, finishAll.length) &&
      finishAll[index] &&
      finishAll[index].flag &&
      finishAll[index].flag1
    ) {
      finishAll[index].flag = false; // 整体码垛标志位
      finishAll[index].flag1 = false; // 整体码垛标志位
    }
    // 检查索引有效性 单个码垛完成
    if (
      isValidIndex(index, finishOne.length) &&
      finishOne[index] &&
      finishOne[index].flag &&
      finishOne[index].flag1
    ) {
      finishOne[index].flag = false; // 整体码垛标志位
      finishOne[index].flag1 = false; // 整体码垛标志位
    }
    // 清除数据标志位
    if (isValidIndex(index, clearCount.length) && clearCount[index]) {
      clearCount[index].flag = false; // 清除数据标志位
    }
    // 检查索引有效性 清除拍照
    if (isValidIndex(index, cameraCount.length) && cameraCount[index]) {
      cameraCount[index].flag = false; // 拍照标志位
      cameraCount[index].value = 0; // 拍照次数
    }
  } else if (way == 2) {
    // 拍照的时候也去检测
    // 全部码垛完成;
    if (
      isValidIndex(index, finishAll.length) &&
      finishAll[index] &&
      finishAll[index].flag &&
      finishAll[index].flag1
    ) {
      finishAll[index].flag = false; // 整体码垛标志位
      finishAll[index].flag1 = false; // 整体码垛标志位
    }
    // 检查索引有效性 单个码垛完成
    if (
      isValidIndex(index, finishOne.length) &&
      finishOne[index] &&
      finishOne[index].flag &&
      finishOne[index].flag1
    ) {
      finishOne[index].flag = false; // 整体码垛标志位
      finishOne[index].flag1 = false; // 整体码垛标志位
    }
  }
}

/**
 * 写入浮点数数组到指定的寄存器地址
 * @param {object} client - Modbus 客户端实例
 * @param {number} startAddress - 起始地址
 * @param {number[]} values - 要写入的数值数组
 * @returns {Promise<boolean>} 写入是否成功
 */
async function writeFloatArrayToRegisters(client, startAddress, values) {
  if (!client || !client.isConnected) {
    logger.warn(`客户端未连接，跳过写入寄存器地址 ${startAddress}`);
    return false;
  }

  if (typeof startAddress !== "number" || !Array.isArray(values)) {
    logger.error("起始地址必须是数字，值必须是数组");
    return false;
  }

  // 重试机制
  return retryOperation(async () => {
    // 使用增强的写入方法
    const result = await client.write32BitFloats(startAddress, values);
    if (result) {
      return true;
    } else {
      logger.error(`写入浮点数组到地址 ${startAddress} 失败`);
      return false;
    }
  }, 3);
}

/**
 * 重试操作
 * @param {function} operation - 要执行的操作
 * @param {number} maxRetries - 最大重试次数
 * @returns {Promise<any>} 操作结果
 */
async function retryOperation(operation, maxRetries) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (err) {
      logger.error(`操作失败 (尝试 ${attempt}/${maxRetries}):`, err.message);
      if (attempt < maxRetries) {
        logger.warn(`操作失败，等待后重试...`);
        await new Promise((resolve) => setTimeout(resolve, 500 * attempt));
      }
    }
  }
  return false;
}

/**
 * 轮询读取 Modbus 寄存器数据
 * @param {object} client - Modbus 客户端实例
 * @param {number} startAddress - 起始地址
 * @param {number} totalRegisters - 总寄存器数
 * @param {number} batchSize - 批量读取大小
 * @returns {Promise<array|null>} 读取到的数据
 */
async function pollRegisters(
  client,
  startAddress,
  totalRegisters,
  batchSize = BATCH_SIZE
) {
  // 参数验证
  if (!client || !client.isConnected) {
    logger.warn(`客户端未定义，跳过读取地址 ${startAddress}`);
    return null;
  }

  if (typeof startAddress !== "number" || typeof totalRegisters !== "number") {
    logger.error("起始地址和总寄存器数必须是数字");
    return null;
  }

  // 重试机制
  return retryOperation(async () => {
    const allData = [];

    for (let i = 0; i < totalRegisters; i += batchSize) {
      const currentStart = startAddress + i;
      const currentCount = Math.min(batchSize, totalRegisters - i);

      try {
        const data = await client.readInputRegisters(
          currentStart,
          currentCount
        );
        allData.push(...data);
      } catch (error) {
        logger.error(
          `读取寄存器 ${currentStart} - ${
            currentStart + currentCount - 1
          } 失败:`,
          error.message
        );
        // 特殊处理Modbus异常3
        if (error.modbusCode === 3) {
          // Modbus Exception 3: Illegal data value
          logger.error(`检测到Modbus异常3，寄存器地址: ${currentStart}`);
          logger.error("该寄存器地址在PLC中不可访问，建议检查PLC配置");

          // // 如果是标志位寄存器读取失败
          // if (
          //   currentStart === flagList[0] &&
          //   currentCount === flagList.length
          // ) {
          //   logger.error("标志位寄存器(32,33)读取失败，这会影响写入操作");
          //   logger.error("建议检查PLC是否支持从地址32开始的读取操作");
          //   // 对于标志位寄存器，返回默认值0
          //   allData.push(0, 0);
          //   continue; // 跳过后续处理
          // }

          // 对于其他寄存器，用0填充不可读取的寄存器
          allData.push(...new Array(currentCount).fill(0));
        }

        // // 如果是寄存器32,33读取失败，特别记录
        // if (startAddress === 32 && totalRegisters === 2) {
        //   logger.error("标志位寄存器(32,33)读取失败，这会影响写入操作");
        // }
      }
      // 等待
      await new Promise((resolve) => setTimeout(resolve, 550));
    }

    return allData;
  }, 3);
}

/**
 * 处理拍照逻辑
 * @param {number} index - 机器人索引
 * @returns {Promise<void>}
 */
async function photoHandle(index, socket) {
  // 直接执行拍照处理逻辑，避免过多的Promise包装层影响性能
  try {
    await photoHandleInternal(index, socket);
  } catch (error) {
    logger.error(`机器人${index}拍照处理出错:`, error.message);
  }
}

/**
 * 实际的拍照处理逻辑
 * @param {number} index - 机器人索引
 * @returns {Promise<void>}
 */
async function photoHandleInternal(index, socket) {
  try {
    let MechVision = 1;

    // 检查索引有效性
    if (!isValidIndex(index, aryModbusStatusList.length)) {
      logger.error("photoHandle: 无效的索引", index);
      return;
    }

    const {
      robotStatus,
      robotPosition,
      robotPhotoStatus,
      robotAllFinished,
      robotOneFinished,
    } = modbusStatusHandle(index);

    // 连接相机获取相机数据
    if (
      robotStatus == 1 &&
      robotPosition == 2 &&
      robotPhotoStatus == 1 &&
      robotOneFinished != 1 &&
      cameraCount[index] &&
      cameraCount[index].value < CAMERA_MAX_RETRY && // 使用优化后的重试次数
      !cameraCount[index].flag
    ) {
      const cameraClient = cameraList[index];
      logger.info("相机实例", cameraClient);
      const reqItem = reqList[index];
      if (!cameraClient) {
        logger.warn("未找到相机客户端实例");
        return;
      }

      // 拼接命令行
      let statusData = aryModbusStatusList[index];
      if (!statusData) {
        logger.warn("状态数据为空");
        return;
      }

      const aryDosNumber = [
        statusData[10],
        statusData[11],
        statusData[12],
        statusData[15],
        statusData[13],
      ];

      // aryDosNumber 中的每一个数据都不能为0.00
      let cameraFlagNum = aryDosNumber.every(
        (item) => typeof item === "number" && item !== 0
      );

      if (!cameraFlagNum) {
        logger.info(`对应的机器人返回的坐标是: ${JSON.stringify(statusData)}`);
        return;
      }

      // 减少重试次数并增加间隔时间
      for (let retry = 0; retry <= 2; retry++) {
        // 增加重试次数到3次
        if (retry > 0) {
          // 增加延迟避免过于频繁的重试
          logger.info(`机器人${index}拍照重试第${retry}次`);
          await new Promise((resolve) =>
            setTimeout(resolve, RETRY_INTERVAL * 2)
          ); // 增加等待时间
        }

        // 确保所有值都存在
        if (
          statusData[10] === undefined ||
          statusData[11] === undefined ||
          statusData[12] === undefined ||
          statusData[15] === undefined ||
          statusData[14] === undefined ||
          statusData[13] === undefined
        ) {
          logger.warn("状态数据不完整");
          break;
        }

        const cameraDos = `101,${MechVision},0,2,${statusData[10]},${
          statusData[11]
        },${statusData[12]},${statusData[15]},${(statusData[14] || 0).toFixed(
          2
        )},${(statusData[13] || 0).toFixed(2)}`;
        logger.info(`拍照命令: ${cameraDos}`);
        try {
          // 添加相机通信超时控制，增加到10秒
          const result = await Promise.race([
            cameraClient.sendMessage(cameraDos),
            new Promise((_, reject) =>
              setTimeout(() => reject(new Error("相机命令发送超时")), 10000)
            ),
          ]);

          if (!result || !result.data) {
            throw new Error("相机返回空数据");
          }

          let data = result.data.replace(/\r/g, "");
          const dataArray = data.split(",");
          data = dataArray[1];

          if (data && data.includes("1102")) {
            if (cameraCount[index] && !cameraCount[index].flag) {
              cameraCount[index].flag = true;
              queue[index] = 1;
            }

            // 添加超时控制，增加到8秒
            const resultData = await Promise.race([
              cameraClient.sendMessage("102,1"),
              new Promise((_, reject) =>
                setTimeout(() => reject(new Error("相机数据请求超时")), 8000)
              ),
            ]);

            if (!resultData || !resultData.data) {
              throw new Error("相机返回空数据");
            }

            let ary = resultData.data.replace(/\r/g, "");
            ary = ary.split(",");
            logger.info(`相机返回的数据: ${JSON.stringify(ary)}`);

            const aryLong = parseFloat(ary[13]) || 0;
            const aryWide = parseFloat(ary[14]) || 0;
            const aryHeight = parseFloat(ary[15]) || 0;
            const aryRz = parseFloat(ary[8]) || 0;
            const writingConfigItem = writingConfig[index];
            if (!writingConfigItem) {
              logger.warn("写入配置项不存在");
              break;
            }

            const flagCamera =
              Math.abs(writingConfigItem[1] - aryLong) < DIFF_VALUE &&
              Math.abs(writingConfigItem[2] - aryWide) < DIFF_VALUE &&
              Math.abs(writingConfigItem[3] - aryHeight) < DIFF_VALUE;

            logger.info(
              `拍照尺寸与真实值的相差尺寸 数据库长${
                writingConfigItem[1]
              },拍照尺寸长${aryLong} 
              差值：${writingConfigItem[1] - aryLong} ===
              数据库宽：${writingConfigItem[2]},
              拍照尺寸宽${aryWide} 
              差值：${writingConfigItem[2] - aryWide} ===
              数据库高：${writingConfigItem[3]},
              拍照尺寸高${aryHeight} 
              差值：${writingConfigItem[3] - aryHeight}
              `
            );

            if (flagCamera) {
              const valueFlag = false; // false 表示传递真实值 ；true:表示传递偏移值
              const offSetLongValue = (aryLong - STATIC_SIZE) / 2;
              const offSetWideValue = (aryWide - STATIC_SIZE) / 2;
              const offSetHeightValue = (aryHeight - STATIC_SIZE) / 2;
              const centerPoint = [
                parseFloat(ary[5]) || 0,
                parseFloat(ary[6]) || 0,
                parseFloat(ary[7]) || 0,
              ];
              // 等待现场验证，具体需要真实值还是偏移值
              const offSetLong = valueFlag ? offSetLongValue : aryLong;
              const offSetWide = valueFlag ? offSetWideValue : aryWide;
              const offSetHeight = valueFlag ? offSetHeightValue : aryHeight;
              // 实际中心点X,中心点Y，中心点z 实际长，实际宽，实际高，
              const photoData = [
                ...centerPoint,
                offSetLong,
                offSetWide,
                offSetHeight,
              ];

              // 判断区域
              const lineNameFlag = checkPointInArea(
                processingProducts[index].lineName,
                parseFloat(ary[5]),
                parseFloat(ary[6]),
                parseFloat(ary[7])
              );
              logger.info(`判断区域是否正确${lineNameFlag}`);
              logger.info(
                `判断区域: ${processingProducts[index].lineName}, ${parseFloat(
                  ary[5]
                )}, ${parseFloat(ary[6])}, ${parseFloat(ary[7])}`
              );

              if (
                writingConfig[index] &&
                photoData.every((item) => {
                  return item !== 0;
                }) &&
                offSetLong &&
                offSetWide &&
                offSetHeight &&
                lineNameFlag
              ) {
                writingConfig[index].splice(6, photoData.length, ...photoData);
                writingConfig[index].splice(13, 1, 1); // 拍照完成位
                writingConfig[index].splice(17, 1, 0); // 数据发送位 置为0
                writingConfig[index].splice(18, 1, aryRz); // 旋转角度RZ

                // 重置所有标志位 拍照的时候看看码垛完成是否通知完成，通知完成就再次清除
                resetFlags(index, 2);
                const compareParams = {
                  sn: processingProducts[index].sn,
                  pId: writingConfig[index][0], // 产品Id
                  beUsed: processingProducts[index].beUsed, // 应用
                  long: writingConfig[index][1], // 默认长
                  wide: writingConfig[index][2], // 默认宽
                  height: writingConfig[index][3], // 默认高
                  clong: writingConfig[index][9], // 实际长
                  cwide: writingConfig[index][10], // 宽
                  cheight: writingConfig[index][11], // 高
                  difflong: writingConfig[index][1] - writingConfig[index][9],
                  diffwide: writingConfig[index][2] - writingConfig[index][10],
                  diffheight:
                    writingConfig[index][3] - writingConfig[index][11],
                  cX: writingConfig[index][6], // 中心点X
                  cY: writingConfig[index][7], // 中心点Y
                  cZ: writingConfig[index][8], // 中心点Z
                  cOZ: writingConfig[index][18], // 拍照时Z轴偏移值
                  rX: statusData[10],
                  rY: statusData[11],
                  rZ: statusData[12],
                  rEX: statusData[13],
                  rEY: statusData[14],
                  rEZ: statusData[15],
                };

                // 异步处理相机数据插入，不阻塞主流程
                insertCameraCompareData(compareParams)
                  .then((resultCompare) => {
                    // logger.info("相机数据插入处理", resultCompare);
                  })
                  .catch((err) => {
                    logger.error("相机数据插入失败", err);
                  });
              }
            } else {
              logger.info("拍照尺寸相差过大");
              cameraCount[index].value++;
              cameraCount[index].flag = false;
              queue[index] = 0;
            }
            // 成功处理后退出循环
            break;
          } else {
            if (cameraCount[index]) {
              cameraCount[index].value++;
            }
            logger.info("相机返回的数据错误", data);
            if (
              cameraCount[index] &&
              cameraCount[index].value >= CAMERA_MAX_RETRY
            ) {
              logger.info("相机拍照次数已达最大重试次数");
              break;
            }
          }
        } catch (error) {
          logger.error("相机通信错误:", error.message);
          if (cameraCount[index]) {
            cameraCount[index].value++;
          }
          // 在最后一次重试后仍然失败才记录日志
          if (
            cameraCount[index] &&
            cameraCount[index].value >= CAMERA_MAX_RETRY
          ) {
            logger.info(`机器人${index}相机通信错误且已达最大重试次数`);
            break;
          } else if (retry < 2) {
            // 如果不是最后一次重试，继续重试
            logger.info(`机器人${index}相机通信错误，准备重试`);
            continue;
          }
          break;
        }
      }
    }
  } catch (error) {
    logger.error("处理拍照逻辑时出错:", error.message, JSON.stringify(error));
  }
}

async function clearHandle(index, socket) {
  try {
    logger.info("进入到了清除", index);
    // 检查索引有效性
    if (!isValidIndex(index, aryModbusStatusList.length)) {
      logger.error("photoHandle: 无效的索引", index);
      return;
    }

    const {
      robotStatus,
      robotPosition,
      robotPhotoStatus,
      robotAllFinished,
      robotOneFinished,
    } = modbusStatusHandle(index);

    //清理数据
    for (let i = 0; i < writingConfig[index].length; i++) {
      writingConfig[index][i] = 0;
    }

    // 重置所有标志位
    resetFlags(index, 1);
    // 清空传给plc 的数据
    clearCount[index].flag = true;
  } catch (error) {
    logger.info("清理数据失败", error);
  }
}

// 单个机器人数据写入函数
async function writeSingleRobotData(client, robotIndex) {
  try {
    // 参数验证
    if (!client || !client.isConnected) {
      logger.warn(`客户端未连接，跳过机器人${robotIndex}数据写入`);
      return false;
    }

    // 获取该机器人对应的寄存器地址
    const registerAddress = writeModBusList[robotIndex][0] - 1;
    const dataToWrite = writingConfig[robotIndex];

    // 重试机制
    const success = await retryOperation(async () => {
      await writeFloatArrayToRegisters(client, registerAddress, dataToWrite);
      return true;
    }, 3);

    if (!success) {
      logger.error(`机器人${robotIndex}数据写入多次尝试后仍然失败`);
      return false;
    }

    return true;
  } catch (error) {
    logger.error(`机器人${robotIndex}数据写入过程中出错:`, error.message);
    return false;
  }
}

/**
 * 提供modbus 状态
 * @param {*} index
 * @returns
 */
function modbusStatusHandle(index) {
  try {
    // 参数验证
    if (typeof index !== "number" || index < 0 || index >= MAX_ROBOTS) {
      logger.error("modbusStatusHandle: 无效的索引", index);
      // 返回默认状态
      return getDefaultRobotStatus();
    }

    // 判断aryModbusStatusList
    let modbusStatusList = aryModbusStatusList[index];
    let finishOneFlagObj = finishOne[index];

    if (!modbusStatusList) {
      logger.warn("modbusStatusHandle: 状态列表为空", index);
      // 返回默认状态
      return getDefaultRobotStatus();
    }

    let robotStatus = modbusStatusList[4] || 0; //机器人状态
    let robotPosition = modbusStatusList[5] || 0; //机器人位置
    let robotPhotoStatus = modbusStatusList[3] || 0; // 是否拍照
    let robotAllFinished = modbusStatusList[7] || 0; // 整条码垛线是否完成
    let robotOneFinished = modbusStatusList[8] || 0; // 单个码垛线是否完成
    let robotOneFinishedFlag = checkFlags(finishOneFlagObj); // 查看是否完成

    return {
      robotStatus,
      robotPosition,
      robotPhotoStatus,
      robotAllFinished,
      robotOneFinished,
      robotOneFinishedFlag,
      finishOneFlagObj,
    };
  } catch (error) {
    logger.error("获取modbus状态时出错:", error.message);
    return getDefaultRobotStatus();
  }
}

function checkFlags(finishOneFlagObj) {
  // 如果两个都为true或都为false，返回false
  if (
    (finishOneFlagObj.flag === true && finishOneFlagObj.flag1 === true) ||
    (finishOneFlagObj.flag === false && finishOneFlagObj.flag1 === false)
  ) {
    return false;
  }
  // 否则返回true
  return true;
}

/**
 * 写机器人数据
 * @param {object} client - Modbus 客户端实例
 */
async function writeRobotHandle(client, socket) {
  try {
    // 读标志位，用于写入机器人数据
    // let flagValue = await pollRegisters(client, flagList[0], flagList.length);
    // 并行处理所有机器人的拍照和完成信号，确保互不影响
    const robotPromises = [];
    for (let i = 0; i < aryModbusStatusList.length; i++) {
      // 确保状态列表存在且有效
      if (aryModbusStatusList[i] && aryModbusStatusList[i][4] == 1) {
        // 直接并行执行，避免过多的Promise包装层
        robotPromises.push(photoHandle(i, socket));
        robotPromises.push(finishToWcsHandle(i, socket));
      }
    }

    // 使用Promise.allSettled确保所有机器人都能完成处理，即使有错误也不会中断其他机器人
    await Promise.allSettled(robotPromises);

    // 并行执行所有机器人的写入操作，提高并发处理能力
    // 但需要检查对应的机器人是否处于运行状态
    const writePromises = [];
    for (let i = 0; i < MAX_ROBOTS; i++) {
      const { robotStatus } = modbusStatusHandle(i);
      // 仅当机器人处于运行状态时才执行写入操作
      if (robotStatus === 1) {
        writePromises.push(writeSingleRobotData(client, i));
      } else {
        //logger.info(`机器人${i}处于非运行状态，跳过写入`);
      }
    }

    const writeResults = await Promise.all(writePromises);
    const successfulWrites = writeResults.filter(
      (result) => result === true
    ).length;

    logger.info(
      `写入完成: ${successfulWrites}/4 个机器人数据写入成功`,
      writingConfig
    );
  } catch (error) {
    logger.error("写入机器人数据时出错:", error.message);
  }
}

/**
 * 读机器人状态
 * @param {object} client - Modbus 客户端实例
 */
async function readStatusListHandle(client, socket) {
  try {
    // // 用于存储 flag 的值
    // let flagValue = null;
    // // 读取标志位 用于获取读机器人数据 同步读取数据
    // flagValue = await pollRegisters(client, flagList[0], flagList.length);

    // 如果flagValue为null，可能是PLC尚未准备好
    // if (flagValue === null) {
    //   logger.warn("PLC可能尚未完全准备好，跳过本轮读取");
    //   return;
    // }
    //   logger.info(`flagValue的值：${flagValue[0]}`);

    // 首先尝试读取全部200个寄存器
    let statusList = await pollRegisters(client, 0, 200);

    // 如果读取失败，尝试只读取120个寄存器
    if (statusList === null) {
      logger.warn("读取200个寄存器失败，尝试读取前120个寄存器");
      statusList = await pollRegisters(client, 0, 120);
    }

    // 如果statusList为null，可能是PLC尚未完全准备好
    if (statusList === null) {
      logger.warn("PLC可能尚未完全准备好，跳过状态列表读取");
      return;
    }

    if (!statusList) {
      logger.warn("未能读取到状态列表");
      return;
    }

    aryModbusStatusList = [];
    // 获取机器人状态列表，根据实际读取到的数据长度进行处理
    const groupSize = 25;
    const groupsNeeded = Math.min(8, Math.ceil(statusList.length / groupSize)); // 最多处理8组（200个寄存器）或根据实际数据长度

    for (let j = 0; j < groupsNeeded; j++) {
      const startIdx = j * groupSize;
      const endIdx = Math.min(startIdx + groupSize, statusList.length);
      const status = statusList.slice(startIdx, endIdx);

      // 如果数据不足25个，用0填充
      while (status.length < groupSize) {
        status.push(0);
      }

      aryModbusStatusList.push(status);
    }
    logger.info("赋值后的状态列表：", aryModbusStatusList);
  } catch (error) {
    logger.error("读取机器人状态时出错:", error.message);
  }
}

// 码垛完成
async function finishToWcsHandle(index, socket) {
  try {
    // 检查索引有效性
    if (!isValidIndex(index, aryModbusStatusList.length)) {
      logger.error("finishToWcsHandle: 无效的索引", index);
      return;
    }

    const {
      robotStatus,
      robotPosition,
      robotPhotoStatus,
      robotAllFinished,
      robotOneFinished,
    } = modbusStatusHandle(index);

    if (
      robotStatus == 1 &&
      robotPosition == 1 &&
      robotOneFinished == 1 &&
      finishOne[index] &&
      !finishOne[index].flag &&
      queue[index] == 1
    ) {
      finishOne[index].flag1 = true;
      // 整体码垛完成
      // 给wcs 发送信息
      // 根据id 查询到产品，然后把产品的数据发送给wcs
      if (!writingConfig[index]) {
        logger.info("写入配置不存在");
        return;
      }

      let id = writingConfig[index][0];
      logger.info("整剁完成找到的id", id);
      if (!id) {
        logger.info("没有找到id，无法发送数据给wcs");
        return;
      }

      // 异步获取产品数据，不阻塞主流程
      getProductionById(id)
        .then(async (productionData) => {
          if (!productionData) return;

          const reqItem = reqList[index];

          // 并行执行所有可以并行的操作，减少总耗时
          const updateProductionPromise = updateProductionById(reqItem, id);
          // const clearHandlePromise = clearHandle(index, socket);

          // 提前设置标志位，避免重复处理
          finishOne[index].flag = true;
          queue[index] = 2;

          // 并行执行数据库更新和清理操作
          const [updateProductionFlag, clearResult] = await Promise.all([
            updateProductionPromise,
            // clearHandlePromise,
          ]);

          // 如果更新失败，重置标志位
          if (!updateProductionFlag) {
            finishOne[index].flag = false;
            queue[index] = 1;
            logger.info(`码垛完成======`);
          }

          // 并行执行：单个码垛反馈 + 空闲状态更新
          logger.info(`传输线单个码垛完成参数${productionData.sn}`);

          // 使用Promise.allSettled确保即使一个操作失败也不会影响其他操作
          // 并且不等待网络请求完成，直接继续执行
          Promise.allSettled([
            csxOneFinish(reqItem, productionData.sn),
            csxFree(reqItem, productionData),
          ]).catch((err) => {
            logger.error("后台任务执行出错:", err.message);
          });

          // 整体码垛完成逻辑
          if (
            productionData &&
            finishAll[index] &&
            !finishAll[index].flag &&
            robotAllFinished == 1
          ) {
            finishAll[index].flag1 = true;
            const valueIndex = `${productionData.beUsed}${productionData.lineName}`;
            logger.info(`获取wcsData的下标${valueIndex}`);
            const data = {
              taskNo: productionData.palletCode,
              ...wcsData[valueIndex],
            };
            logger.info(
              `库内wcs整体码垛完成传过去的参数,${JSON.stringify(data)}}`
            );
            let flagcsx = false;
            let tarConvey = false;

            // 异步执行传输线反馈，不阻塞主流程
            csxFinishAll(reqItem, productionData.palletCode)
              .then((response) => {
                logger.info(`传输线整体码垛完成${JSON.stringify(response)}`);
                flagcsx = true;
                if (flagcsx && tarConvey) {
                  finishAll[index].flag = true;
                }
              })
              .catch((err) => {
                logger.error("传输线整体码垛完成反馈失败:", err.message);
              });
            // 库内码垛线
            tartConveyTaskArmHandle(data)
              .then((response) => {
                tarConvey = true;
                if (flagcsx && tarConvey) {
                  finishAll[index].flag = true;
                }

                logger.info(`库内wcs 整体码垛完成,${JSON.stringify(response)}`);
              })
              .catch((err) => {
                logger.error("库内WCS通知失败:", err);
                // finishAll[index].flag = true;
              });
          }
        })
        .catch((err) => {
          logger.error("获取产品数据失败:", err);
          // 发生错误时重置标志位
          finishOne[index].flag = false;
          queue[index] = 1;
        });
    }
  } catch (error) {
    logger.error("处理码垛完成时出错:", error.message);
  }
}
/**
 * 开始轮询并写入数据到 aryModbusStatusList
 * @param {WebSocket} socket - 当前 WebSocket 实例
 * @param {object} client - Modbus 客户端实例
 */
async function startPollingAndWriting(socket, client) {
  try {
    const content = `轮询`;
    const payload = JSON.stringify({
      id: "",
      status: "1",
      ip: client.ip,
      port: client.port,
      type: "",
      beUsed: "",
    });

    // 初始化 aryModbusStatusList，所有值置为 0
    const zeroArray = new Array(100).fill(0);
    aryModbusStatusList = [];
    for (let j = 0; j < zeroArray.length; j += 25) {
      const status = zeroArray.slice(j, j + 25);
      aryModbusStatusList.push(status);
    }

    const pollNext = async () => {
      try {
        if (!socket || !socket.connected) {
          logger.info(
            "websocket 已经断开，停止轮询并写入数据到 aryModbusStatusList"
          );
          return;
        }

        // 检查客户端连接状态
        if (!client || !client.isConnected) {
          logger.info("Modbus客户端未连接，等待重连...");
          setTimeout(pollNext, 5000);
          return;
        }

        // 读数据
        await readStatusListHandle(client, socket);
        if (client.isConnected) {
          // 更新前端状态
          const fullData = aryModbusStatusList.flat();
          if (socket && socket.connected) {
            socket.emit("modBusStatus", {
              message: "modBus协议，机器人状态",
              inputData: fullData,
            });
          } else {
            // 如果断线，则重新连接
            logger.info("断线啦");
          }
        }

        // 等待
        await new Promise((resolve) => setTimeout(resolve, 550));
        // 写数据
        await writeRobotHandle(client, socket);

        // 继续下一次轮询
        setTimeout(pollNext, POLLING_INTERVAL); // 使用优化后的轮询间隔
      } catch (error) {
        logger.error("轮询过程中出错:", error.message);
        // 出错时使用较长的间隔再试
        setTimeout(pollNext, 3000);
      }
    };

    // 开始第一次轮询
    await pollNext();
  } catch (error) {
    logger.error("启动轮询时出错:", error.message);
  }
}

//写入产品信息
function writeProData(proData, cameraClient, req) {
  try {
    // 验证参数
    if (!proData) {
      logger.error("writeProData: proData 参数为空");
      return;
    }

    let lineNum = 0;
    if (proData.lineName == "A") {
      lineNum = 1;
    } else if (proData.lineName == "B") {
      lineNum = 2;
    }

    const data = [
      proData.id || 0, // id
      proData.long || 0, // 默认长
      proData.wide || 0, // 默认宽
      proData.height || 0, // 默认高
      proData.palletizingNum || 0, // 码垛层数
      proData.layerNum || 0, // 每件个数
      0, // 中心点x
      0, // 中心点y
      0, // 中心点z
      0, // 实际长
      0, // 实际宽
      0, // 实际高
      1, // 托盘到位状态
      0, // 拍照完成
      proData.grippingDirection || 0, // 抓取方向
      proData.presetsNum || 0, // 当前产品码垛数量
      lineNum, // 码垛位置
      1, // 数据发送
      0, // 中心点RZ
      0, // 托盘到B位
      0, // 是否启用 1为启用 2为停用
      0, //  备用
      0, // 备用
      0, // 备用
      0, // 备用
    ];

    // 检查索引有效性
    const index = (proData.beUsed || 1) - 1;
    if (!isValidIndex(index, writingConfig.length)) {
      logger.error("writeProData: 无效的beUsed值", proData.beUsed);
      return;
    }

    const {
      robotStatus,
      robotPosition,
      robotPhotoStatus,
      robotAllFinished,
      robotOneFinished,
    } = modbusStatusHandle(proData.beUsed - 1);

    // 只有当机器人状态为1且位置为1时才写入数据
    if (robotStatus == 1 && robotPosition == 1) {
      // 检查是否已经在处理该产品，避免重复写入
      const existingProduct = processingProducts[index];
      if (existingProduct && existingProduct.sn === proData.sn) {
        logger.info(`产品 ${proData.sn} 已在处理中，跳过重复写入`);
        return;
      }

      if (writingConfig[index]) {
        writingConfig.splice(index, 1, data);
      }

      // 检查索引有效性
      if (isValidIndex(index, cameraList.length)) {
        cameraList.splice(index, 1, cameraClient);
        reqList.splice(index, 1, req);
      }

      // 重置所有标志位
      resetFlags(index, 0);
      queue[index] = 0;
      processingProducts.splice(index, 1, proData);
      logger.info(`产品 ${proData.sn} 写入完成`);
    } else {
      logger.info(`机器人状态不满足条件，跳过写入产品 ${proData.sn}`);
    }
  } catch (error) {
    logger.error("写入产品数据时出错:", error.message);
  }
}

// 获取要写入的数据
async function getWritingConfig() {
  return writingConfig;
}

// 获取plc 的状态
async function getPlcStatus() {
  return aryModbusStatusList;
}

// 获取相机拍照状态
async function getCameraCount() {
  return cameraCount;
}

module.exports = {
  startPollingAndWriting,
  aryModbusStatusList,
  writingConfig,
  writeProData,
  modbusStatusHandle,
  writeFloatArrayToRegisters,
  queue,
  getWritingConfig,
  getPlcStatus,
  getCameraCount,
  cameraCount,
};
